/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package csci6450.chickenFriedFS.nuggetServer.threads;

import csci6450.chickenFriedFS.nuggetCore.Nugget;
import csci6450.chickenFriedFS.nuggetCore.NuggetConstants;
import csci6450.chickenFriedFS.nuggetCore.NuggetUtilities;
import csci6450.chickenFriedFS.nuggetServer.NuggetFileStoreManager;
import csci6450.chickenFriedFS.nuggetServer.NuggetServer;
import csci6450.chickenFriedFS.nuggetServer.NuggetServerLog;
import csci6450.chickenFriedFS.nuggetServer.RuntimeSettings;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author jacobschoen
 */
public class NuggetServerReplicationListener extends Thread {
    int runningThreads = 0;
    /**
     * Socket for this server to run on.
     */
    private ServerSocket serverSocket;

    public NuggetServerReplicationListener() throws IOException {
        this.serverSocket = new ServerSocket(RuntimeSettings.getInstance().getReplicationPort());
        System.out.println("Server listening for replication requests on port " + RuntimeSettings.getInstance().getReplicationPort() + ".");
    }

    @Override
    public void run() {
        try {
            Socket client = null;
            java.net.InetAddress i = java.net.InetAddress.getLocalHost();
            String hostname = i.getHostAddress();
            while (true) {
                try {
                    client = this.serverSocket.accept();
                    Connect c = new Connect(client);
                    c.start();
                } catch (Exception e) {
                    e.printStackTrace();
                    if (client != null) {
                        try {
                            client.close();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
        } catch (UnknownHostException ex) {
            Logger.getLogger(NuggetServerReplicationListener.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class Connect extends Thread {

        private Socket client = null;
        private ObjectInputStream inputStream = null;
        private ObjectOutputStream outputStream = null;

        public Connect(Socket clientSocket) {
            this.client = clientSocket;
            try {
                this.inputStream = new ObjectInputStream(this.client.getInputStream());
                this.outputStream = new ObjectOutputStream(this.client.getOutputStream());
            } catch (Exception e1) {
                try {
                    this.client.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void run() {
            runningThreads = runningThreads +1;
            ServerSocket socket = null;
            Socket fileClient = null;
            try {
                //Integer port = NuggetServer.getInstance().getAvailablePort(NuggetServer.getInstance().STARTING_PORT);
                Integer port = NuggetServer.getInstance().STARTING_PORT;
                boolean done = false;
                while (!done) {
                    done = true;
                    try {
                        socket = new ServerSocket(port);
                    } catch (Exception e) {
                        done = false;
                        port = port+1;
                    }
                }
                done = false; //sends the port number for the client to use to upload file.
                this.outputStream.writeObject(port);
                // close streams and connections
                //open the socket to get the file
                this.client.close();
                Nugget nugget = null;
                fileClient = socket.accept();
                NuggetUtilities.memCheck(runningThreads);
                ObjectInputStream ois = new ObjectInputStream(fileClient.getInputStream());
                nugget = (Nugget) ois.readObject();

                if (nugget != null) {
                    this.outputStream = new ObjectOutputStream(fileClient.getOutputStream());
                    try {
                        long offset = NuggetFileStoreManager.getInstance().addNugget(nugget.getNugget());
                        if (offset < 0) {
                            //this looks stupid, but is a hack since for some reason it never gets the
                            //offset right for the first chunk sent. But it works
                            offset = NuggetFileStoreManager.getInstance().addNugget(nugget.getNugget());
                        }
                        nugget.setRepNuggetOffset(offset);
                        NuggetServerLog.getInstance().addNugget(nugget);
                        //tell the client it is all good.
                        this.outputStream.writeObject(NuggetConstants.SUCCESS);
                        this.outputStream.flush();
                    } catch (Exception exception) {
                        this.outputStream.writeObject(NuggetConstants.FAILURE);
                        this.outputStream.flush();
                    }
                } else {
                    this.outputStream.writeObject(NuggetConstants.FAILURE);
                    this.outputStream.flush();
                }
                done = true;

            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fileClient != null) {
                    try {
                        fileClient.close();
                    } catch (IOException ex) {
                        Logger.getLogger(NuggetServerReplicationListener.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException ex) {
                        Logger.getLogger(NuggetServerReplicationListener.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    runningThreads = runningThreads -1;
                }
            }
        }
    }
}
